/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/** @defgroup select Select
* @ingroup libc
*/

#ifndef _SYS_SELECT_H_
#define _SYS_SELECT_H_

#ifndef __LITEOS__
#include <linux/time.h>
#else
#include <liteos/time.h>
#endif
#include <signal.h>
#include <sys/cdefs.h>
#include <sys/types.h>

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */


#ifndef __LITEOS__
#define FD_SETSIZE 1024
#else
#include "vfs_config.h"
#endif
#define NFDBITS (8 * (int)sizeof(unsigned long))
#define __FDSET_LONGS (FD_SETSIZE/NFDBITS)

typedef struct {
  unsigned long fds_bits[__FDSET_LONGS];
} fd_set;

#define __FDELT(fd) ((fd) / NFDBITS)
#define __FDMASK(fd) (1UL << ((fd) % NFDBITS))
#define __FDS_BITS(set) (((fd_set*)(set))->fds_bits)
#define __FD_CLR(fd, set) (__FDS_BITS(set)[__FDELT(fd)] &= ~__FDMASK(fd))
#define __FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
#define __FD_ISSET(fd, set) ((__FDS_BITS(set)[__FDELT(fd)] & __FDMASK(fd)) != 0)

/* Inline loop so we don't have to declare memset. */
#define FD_ZERO(set) \
  do { \
    size_t __i; \
    for (__i = 0; __i < __FDSET_LONGS; ++__i) { \
      (set)->fds_bits[__i] = 0; \
    } \
  } while (0)

extern void __FD_CLR_chk(int, fd_set*, size_t);
extern void __FD_SET_chk(int, fd_set*, size_t);
extern int __FD_ISSET_chk(int, const fd_set*, size_t);

#if defined(__BIONIC_FORTIFY)
#define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
#define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
#define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
#else
#define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
#define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
#define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
#endif /* defined(__BIONIC_FORTIFY) */

/**
* @ingroup  select
* @par Description:
*
* The select function examines the file descriptor sets whose addresses are passed in the readfds, writefds, and errorfds parameters to see whether
* some of their descriptors are ready for reading, are ready for writing, or have an exceptional condition pending, respectively. \n\n
*
* Upon successful completion, the select function would modify the objects pointed to by the readfds, writefds, and errorfds arguments to indicate
* which file descriptors are ready for reading, ready for writing, or have an error condition pending, respectively, and the total number of ready descriptors
* in all the output sets would be returned. For each file descriptor less than nfds, the corresponding bit shall be set upon successful completion if it was
* set on input and the associated condition is true for that file descriptor. If none of the selected descriptors are ready for the requested operation, the
* select function shall block until at least one of the requested operations becomes ready, until the timeout occurs. The timeout parameter controls how
* long the select function shall take before timing out. If the timeout parameter is not a null pointer, it specifies a maximum interval to wait for the selection
* to complete. If the specified time interval expires without any requested operationbecoming ready, the function would return. If the timeout parameter is
* a null pointer, then the call to select would block indefinitely until at least one descriptor meets the specified criteria.\n\n

* A descriptor shall be considered ready for reading when a call to an input function with O_NONBLOCK clear would not block, whether or not the function
* would transfer data successfully. (The function might return data, an end-of-file indication, or an error other than one indicating that it is blocked, and
* in each of these cases the descriptor shall be considered ready for reading). If the descriptor refers to a socket, the implied input function is the recvmsg
* function with parameters requesting normal and ancillary data, such that the presence of either type shall cause the socket to be marked as readable.
* The presence of out-of-band data shall be checked if the socket option SO_OOBINLINE has been enabled, as out-of-band data is enqueued with normal data.
* If the socket is currently listening, then it shall be marked as readable if an incoming connection request has been received, and a call to the accept function
* shall complete without blocking.\n\n
*
* A descriptor shall be considered ready for writing when a call to an output function with O_NONBLOCK clear would not block, whether or not the function
* would transfer data successfully. If the descriptor refers to a socket, the implied output function is the sendmsg function supplying an amount of normal
* data equal to the current value of the SO_SNDLOWAT option for the socket. If a non-blocking call to the connect function has been made for a socket, and
* the connection attempt has either succeeded or failed leaving a pending error, the socket shall be marked as writable.\n\n
*
* If a socket has a pending error, it shall be considered to have an exceptional condition pending. Otherwise, what constitutes an exceptional condition is file
* type-specific. For a file descriptor for use with a socket, it is protocol-specific except as noted below. For other file types it is implementation-defined. If the
* operation is meaningless for a particular file type, the select shall indicate that the descriptor is ready for read or write operations, and shall indicate that the
* descriptor has no exceptional condition pending. A socket shall be considered to have an exceptional condition pending if a receive operation with O_NONBLOCK
* clear for the open file description and with the MSG_OOB flag set would return out-of-band data without blocking. (It is protocol-specific whether the MSG_OOB
* flag would be used to read out-of-band data.) A socket shall also be considered to have an exceptional condition pending if an out-of-band data mark is present
* in the receive queue. Other circumstances under which a socket may be considered to have an exceptional condition pending are implementation-defined. \n\n
*
* File descriptors associated with regular files shall always select true for ready to read, ready to write, and error conditions.\n\n
*
* If the readfds, writefds, and errorfds arguments are all null pointers and the timeout argument is not a null pointer, the select() function would block for the
* time specified. If the readfds, writefds, and errorfds arguments are all null pointers and the timeout argument is a null pointer, the select() function returns
* failure immediately.\n\n
*
* File descriptor masks of type fd_set can be initialized and tested with FD_CLR, FD_ISSET, FD_SET, and FD_ZERO. It is unspecified whether each of these
* is a macro or a function. If a macro definition is suppressed in order to access an actual function, or a program defines an external identifier with any of these
* names, the behavior is undefined.\n\n
*
* FD_CLR(fd, set) shall remove the file descriptor fd from the set pointed to by set. If fd is not a member of this set, there is no effect on the set.
* FD_ISSET(fd, set) shall evaluate to non-zero if the file descriptor fd is a member of the set pointed to by set, and shall evaluate to zero otherwise.
* FD_SET(fd, set) shall add the file descriptor fd to the set pointed to by set. If the file descriptor fd is already in this set, there is no effect on the set.
* FD_ZERO(set) shall initialize the descriptor set pointed to by set to the null set. No error is returned if the set is not empty at the time FD_ZERO() is invoked.\n\n
*
* The behavior of these macros is undefined if the fd argument is less than 0 or greater than or equal to FD_SETSIZE, or if fd is not a valid file descriptor,
* or if any of the arguments are expressions with side-effects.\n\n

* @param    nfds       [IN]   the range of descriptors to be tested, all descriptors from zero to nfds-1 in the descriptor sets shall be examined.
* @param    readfds   [IN/OUT]  on input specifies the file descriptors to be checked for being ready to read, and on output indicates which file descriptors are ready to read.
* @param    writefds  [IN/OUT]  on input specifies the file descriptors to be checked for being ready to write, and on output indicates which file descriptors are ready to write.
* @param    errorfds  [IN/OUT]  on input specifies the file descriptors to be checked for error conditions pending, and on output indicates which file descriptors have error conditions pending.
* @param    timeout  [IN]  a maximum interval to wait for the selection to complete.
*
* @attention
* <ul>
* <li>Unlike Linux or other operation system, LiteOS does not support signal mechanism, so the select function can't be interrupted by signal.</li>
* <li>Unlike Linux, LiteOS does not modify the timeout argument to reflect the amount of time not slept on successful completion.</li>
* <li>The select functions support regular files, terminal, device files and sockets. The behavior of select on file descriptors that refer to other types of file is unspecified.</li>
* <li>If the readfds, writefds, errorfds and timeout are all null, the select function returns immediately. But in Linux or other system, the select function
* would block until interrupted by a signal.</li>
* <li>LiteOS don't support TCP urgent data(also used as the out-of-band data), so the caller can not use the select function with errorfds to examine the TCP urgent data.</li>
* <li>It is recommended that the poll function is perferred than the select as the impelmentation of select is based on the pool, so the poll function is more efficient.</li>
* <li>If a file descriptor being monitored by select is closed in another thread, the result is unspecified. On some UNIX systems, select unblocks and returns
* with  an  indication  that  the  file descriptor is ready. On LiteOS, closing the file descriptor in another thread has no effect on select. In summary,
* any application that relies on a particular behavior in this scenario must be considered buggy.</li>
* <li>The timeout will be rounded up to the system clock granularity, on LiteOS, it's the system scheduling tick. So the minimal poll timeout is one
* scheduling tick on LiteOS.</li>
* </ul>
*
* @retval    #>=0   On success, the total number of bits set in the bit masks is retuened. If timeout expires before anything interesting happens, 0 is returned.
* @retval    #-1   On failure, -1 is returned, and errno is set to indicate the error, the file descriptor sets and timeout are unmodified.
* FD_CLR, FD_SET, and FD_ZERO do not return a value. FD_ISSET returns a non-zero value if the bit for the file descriptor fd is set in the file descriptor
* set pointed to by fdset, and 0 otherwise.\n\n
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: One or more of the file descriptor sets specified a file descriptor that is not a valid open file descriptor.</li>
* <li><b>EINVAL</b>: The nfds argument is less than 0 or greater than FD_SETSIZE.</li>
* <li><b>EINVAL</b>: The readfds, writefds, errorfds and timeout are all null.</li>
* <li><b>ENOMEM</b>: Unable to allocate memory for internal tables.</li>
* <li><b>ENOSYS</b>: One or more of the file descriptor sets specified a file descriptor don't support poll operation</li>
* </ul>
*
* @par Dependency:
* <ul><li>sys/select.h</li></ul>
*
* @see  accept | connect | poll | read | recv | send | write
*
* @since Huawei LiteOS V100R001C00
*/
extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
extern int pselect(int, fd_set*, fd_set*, fd_set*, const struct timespec*, const sigset_t*);


#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _SYS_SELECT_H_ */
